<% const { apiConfig, generateResponses, config }=it; %>
  import { message } from "@ctzhian/ui";
  import type { AxiosInstance, AxiosRequestConfig, HeadersDefaults, ResponseType, AxiosResponse } from "axios";
  import axios from "axios";

  export type QueryParamsType = Record<string | number, any>;

    export interface FullRequestParams extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> {
      /** set parameter to `true` for call `securityWorker` for this request */
      secure?: boolean;
      /** request path */
      path: string;
      /** content type of request body */
      type?: ContentType;
      /** query params */
      query?: QueryParamsType;
      /** format of response (i.e. response.json() -> format: "json") */
      format?: ResponseType;
      /** request body */
      body?: unknown;
      }

      export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;

        export interface ApiConfig<SecurityDataType=unknown> extends Omit<AxiosRequestConfig, "data" | "cancelToken"> {
            securityWorker?: (securityData: SecurityDataType | null) => Promise<AxiosRequestConfig | void> |
              AxiosRequestConfig | void;
              secure?: boolean;
              format?: ResponseType;
              }

              export enum ContentType {
              Json = "application/json",
              FormData = "multipart/form-data",
              UrlEncoded = "application/x-www-form-urlencoded",
              Text = "text/plain",
              }

              const redirectToLogin = () => {
              const redirectAfterLogin = encodeURIComponent(location.href);
              const search = `redirect=${redirectAfterLogin}`;
              const pathname = location.pathname.startsWith('/user')
              ? '/user/login'
              : '/login';
              window.location.href = `${pathname}?${search}`;
              };

              type ExtractDataProp<T> = T extends { data?: infer U } ? U : T


                export class HttpClient<SecurityDataType=unknown> {
                  public instance: AxiosInstance;
                  private securityData: SecurityDataType | null = null;
                  private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
                    private secure?: boolean;
                    private format?: ResponseType;

                    constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig<SecurityDataType> = {}) {
                      this.instance = axios.create({ withCredentials: true, ...axiosConfig, baseURL: axiosConfig.baseURL
                      || '' })
                      this.secure = secure;
                      this.format = format;
                      this.securityWorker = securityWorker;
                      this.instance.interceptors.response.use(
                      (response) => {
                      if (response.status === 200) {
                      const res = response.data;
                      if (res.success) {
                      return res.data;
                      }
                      message.error(res.message || "网络异常");
                      return Promise.reject(res);
                      }
                      message.error(response.statusText);
                      return Promise.reject(response);
                      },
                      (error) => {
                      if (error.response?.status === 401) {
                      window.location.href = '/login'
                      localStorage.removeItem('panda_wiki_token')
                      }
                      if (error.code !== 'ERR_CANCELED') {
                      message.error(error.response?.statusText || "网络异常");
                      }
                      return Promise.reject(error.response);
                      },
                      )
                      }

                      public setSecurityData = (data: SecurityDataType | null) => {
                      this.securityData = data
                      }

                      protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig):
                      AxiosRequestConfig {
                      const method = params1.method || (params2 && params2.method)

                      return {
                      ...this.instance.defaults,
                      ...params1,
                      ...(params2 || {}),
                      headers: {
                      ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) ||
                      {}),
                      ...(params1.headers || {}),
                      ...((params2 && params2.headers) || {}),
                      },
                      };
                      }

                      protected stringifyFormItem(formItem: unknown) {
                      if (typeof formItem === "object" && formItem !== null) {
                      return JSON.stringify(formItem);
                      } else {
                      return `${formItem}`;
                      }
                      }

                      protected createFormData(input: Record<string, unknown>): FormData {
                        return Object.keys(input || {}).reduce((formData, key) => {
                        const property = input[key];
                        const propertyContent: any[] = (property instanceof Array) ? property : [property]

                        for (const formItem of propertyContent) {
                        const isFileType = formItem instanceof Blob || formItem instanceof File;
                        formData.append(
                        key,
                        isFileType ? formItem : this.stringifyFormItem(formItem)
                        );
                        }

                        return formData;
                        }, new FormData());
                        }

                        public request = async <T=any, _E=any>({
                          secure,
                          path,
                          type,
                          query,
                          format,
                          body,
                          ...params
                          <% if (config.unwrapResponseData) { %>
                            }: FullRequestParams): Promise<ExtractDataProp<T>> => {
                              <% } else { %>
                                }: FullRequestParams): Promise<AxiosResponse<T>> => {
                                  <% } %>
                                    const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) &&
                                    this.securityWorker && (await this.securityWorker(this.securityData))) || {};
                                    const requestParams = this.mergeRequestParams(params, secureParams);
                                    const responseFormat = (format || this.format) || undefined;

                                    if (type === ContentType.FormData && body && body !== null && typeof body ===
                                    "object") {
                                    body = this.createFormData(body as Record<string, unknown>);
                                      }

                                      if (type === ContentType.Text && body && body !== null && typeof body !==
                                      "string") {
                                      body = JSON.stringify(body);
                                      }
                                      const token = localStorage.getItem('panda_wiki_token') || ''

                                      return this.instance.request({
                                      ...requestParams,
                                      headers: {
                                      Authorization: `Bearer ${token}`,
                                      ...(requestParams.headers || {}),
                                      ...(type && type !== ContentType.FormData ? { 'Content-Type': type } : {}),
                                      },
                                      params: query,
                                      responseType: responseFormat,
                                      data: body,
                                      url: path,
                                      })
                                      };
                                      }
                                      export default new HttpClient({ format: 'json' }).request